var ProcessStack = function(tagID)  {
    var rows = cols = 1,  // initial size
        i = j = 0,
        _pStack = new Array(rows),
        _pStackGraphs = [],
        _pStackValid = true
        _taskComplete = {},
        _taskPriority = {};

    // initialise the stack
    for (; i < cols; i++) {
        _pStack[i]=new Array(rows);
    }
    _pStack[0][0] = tagID;

    function _display() {
        var r = 0, nd;
        console.log("Stack picture: ", tagID);
        for (; r< rows; r++) {
            console.log(_pStack[r]);
        }

        console.log('Stack is ', _pStackValid?'VALID':'NOT VALID');
        for (r=0; r<rows-1; r++) {
            nd = _pStack[r+1][0];
            console.log(_pStackGraphs[r], _taskComplete[nd], _taskPriority[nd]);
        }

        return this;
    }
    function _addCol(tag) {
        var i = 0;

        // add the new column.. extend each row by 1 element  
        for (; i < rows; i++) {
            _pStack[i].push(false);
        }
        _pStack[0][cols] = tag;
        cols++;;
    }
    function _addRow(tag) {
        var i = 1;

        _pStack[rows] = new Array(cols);    // add the new row;
        _pStack[rows][0] = tag;
        for (; i < cols; i++) {
            _pStack[rows][i] = false;    // no dependency by default
        }
        rows++;
    }
    function _addEdge(u, v) {
        // by edge we mean dependency relationship
        // u depends on completion of v
        // edges are defined in row orientation
        if ( u == v ) return this;

        var r = c = 0;

        // get the (u,v) cell in _pStack
        for (; r < rows; r++) {
            if (_pStack[r][0] == u ) break;
        }
        for (; c < cols; c++) {
            if (_pStack[0][c] == v ) break;
        }
        _pStack[r][c] = true;

        return this;
    }
    function _contains(aList, item) {
        return (aList.indexOf(item) > -1)
    }
    function _getEdges(u) {
        // edges are row orientated
        var edgeList = [], rootList = [], r = 0, valid = true;
        rootList.push(u);

        function getNodeEdges(node) {
            var c, r = 1, nd;
            for (; r < rows; r++) {
                if (_pStack[r][0] == node ) break;
            }

            c = 1; // start on the 2nd column as the 1st column is the task ID.
            for (; c < cols; c++) {
                nd = _pStack[0][c];

                if (_pStack[r][c] && valid) {
                    if ( (c!=r) && !_contains(rootList, nd) ) {
                        // don't bother to add to edgList if the node is there already
                        if (!_contains(edgeList, nd) ) edgeList.push(nd);
                        rootList.push(nd);

                        if (!getNodeEdges(nd)) { valid = false; break; }
                    }
                    else {
                        try { throw new Error(['Invalid Process Stack: ',
                            nd, ' and ', node, ' are cyclic'].join('')); }
                        catch (e) { console.log(e.name, e.message); }
                        valid = false;
                        break;
                    }
                }
            }
            // remove the last entry in rootList if you're here.. as it's a leaf node
            // and we should'nt check against it further in our recursive calls

            return valid && rootList.pop();
        }

        getNodeEdges(u);        // start the getting
        return [valid, edgeList];
    }

    function _validateStack() {
        var r, list, nd, i = 0;

        for (r=1; r < rows; r++) {
            nd = _pStack[r][0];
            list = _getEdges(nd);
            _pStackGraphs.push([list[0], nd, list[1]]);
            _taskComplete[nd] = false;
            _taskPriority[nd] = 1;
        }
        for (r=0; r<rows-1; r++) {
            _pStackValid = true;
            if ( !_pStackGraphs[r][0] ) {
                _pStackValid = false;
                break;
            }
        }

        for (r = 1; r<rows; r++) {
            list = _pStackGraphs[r-1][2];
            for (; i < list.length; i++) {
                _taskPriority[list[i]]++;
            }
        }
        return this;
    }

    return {
        addTask: function(tag) { _addRow(tag); _addCol(tag); return this; },
        display: _display,
        addEdge: _addEdge,
        getEdges: _getEdges,
        validateStack: _validateStack
    }
};


var m = ProcessStack('P1');
m.addTask('t1').addTask('t2').addTask('t3').addTask('t4').addTask('t5');
m.addEdge('t1', 't2').addEdge('t1', 't3');
m.addEdge('t2', 't3');
m.addEdge('t3', 't5');
m.addEdge('t4', 't1');

////m.addEdge('t3', 't2');
m.validateStack().display();

////console.dir(m.getEdges('t1'));
////console.dir(m.getEdges('t1'));
